package com.midipad;

import java.io.File;
import java.io.FileInputStream;
import java.net.URI;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.content.Context;
import android.view.View.OnTouchListener;

import com.midipad.controls.Button;
import com.midipad.controls.Fader;
import com.midipad.controls.MidiController;
import com.midipad.controls.Pad;

/**
 * Reads an xml interface file, and create the corresponding controllers
 * @author Tim
 *
 */
public class DomInterfaceReader {
	//elements names
	static final String CONTROLLERS = "controllers";
	static final String CONTROLLER = "controller";
	static final String MIDI_MESSAGES = "midiMessages";
	static final String MIDI_MESSAGE = "midiMessage";

	/**
	 * parse the xml file
	 * @param filePath the absolute path to the xml file
	 * @param context
	 * @param controllers the controllers list to populate
	 * @param touchListener the touchlistener to assign to the created controllers 
	 */
	public static void parse(String filePath, Context context, ArrayList<MidiController> controllers, OnTouchListener touchListener, int viewWidth, int viewHeight) {
		URI uri = URI.create("file://"+filePath);
		File file = new File(uri);
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {//ho man xml sucks...
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document dom = builder.parse(new FileInputStream(file));
            Element root = dom.getDocumentElement();
            root.normalize();
            NodeList controllersItems = root.getElementsByTagName(CONTROLLER);
            float scaleX = (float)viewWidth/Integer.parseInt(root.getAttribute("width"));
            float scaleY = (float)viewHeight/Integer.parseInt(root.getAttribute("height"));
            
            for (int i=0;i<controllersItems.getLength();i++){//for each controller
            	Node controllerItem = controllersItems.item(i);//get the controller
            	if(controllerItem.getNodeType()==Node.ELEMENT_NODE){
	            	MidiController controller = null;
	                int [] midiMessages;
	                int x = 0;
	                int y = 0;
	                int width = 0;
	                int height = 0;
	                String type;
	                NamedNodeMap attributes = controllerItem.getAttributes();
	                type = attributes.getNamedItem("type").getNodeValue();
	                x = (int) (Integer.parseInt(attributes.getNamedItem("x").getNodeValue())*scaleX);
	                y = (int) (Integer.parseInt(attributes.getNamedItem("y").getNodeValue())*scaleY);
	                width = (int) (Integer.parseInt(attributes.getNamedItem("width").getNodeValue())*scaleX);
	                height = (int) (Integer.parseInt(attributes.getNamedItem("height").getNodeValue())*scaleY);
	                
	                NodeList midiMessagesNodes = controllerItem.getChildNodes();
	                //find the real midiMessages node
	                for(int j=0 ; j<midiMessagesNodes.getLength() ; j++){
	                	Node possibleNode = midiMessagesNodes.item(j);
	                	if(possibleNode.getNodeType()==Node.ELEMENT_NODE){
	                		midiMessagesNodes = possibleNode.getChildNodes();
	                		break;
                		}
	                }
	                
	                int nbMidiMessages = 0;
	                //first calculate the number of midi messages
	                for(int j=0 ; j<midiMessagesNodes.getLength() ; j++){
	                	Node MidiMessageNode = midiMessagesNodes.item(j);
	                	if(MidiMessageNode.getNodeType()==Node.ELEMENT_NODE){
	                		nbMidiMessages++;
	                	}
	                }
	                midiMessages = new int[nbMidiMessages*3];
	                //then get the messages
	                int mm=0;
	                for(int j=0 ; j<midiMessagesNodes.getLength() ; j++){
	                	Node midiMessageNode = midiMessagesNodes.item(j);
	                	if(midiMessageNode.getNodeType()==Node.ELEMENT_NODE){
	                		midiMessages[mm++]=Integer.parseInt(midiMessageNode.getAttributes().getNamedItem("statusByte").getNodeValue());
			            	midiMessages[mm++]=Integer.parseInt(midiMessageNode.getAttributes().getNamedItem("data1Byte").getNodeValue());
			            	midiMessages[mm++]=0;
	                	}
	                }
	                if(type.equalsIgnoreCase("PAD")){
	                	controller = new Pad(context, x, y, width, height, midiMessages);
	                }else if(type.equalsIgnoreCase("FADER H")){
	                	controller = new Fader(context, x, y, width, height, midiMessages, Fader.TYPES.HORIZONTAL);
	                }else if(type.equalsIgnoreCase("FADER V")){
	                    	controller = new Fader(context, x, y, width, height, midiMessages, Fader.TYPES.VERTICAL);
	                }else if(type.equalsIgnoreCase("BUTTON T")){
	                	controller = new Button(context, x, y, width, height, midiMessages, Button.TYPES.TOGGLE);
	                }else if(type.equalsIgnoreCase("BUTTON M")){
	                	controller = new Button(context, x, y, width, height, midiMessages, Button.TYPES.MOMENTARY);
	                }
	                controller.setOnTouchListener(touchListener);
	                controllers.add(controller);
            	}
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } 
    }
}
